﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Automation.Peers;
using System.Windows.Automation.Provider;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Media;

namespace Gmantis.Controls.Toolbar
{
    public enum ToolbarOverflow
    {
        None,
        Menu,
        Panel
    }

    public class ToolbarStrip : System.Windows.Controls.ItemsControl
    {
        // Fields
        private ObservableCollection<object> _menuItems;
        public static readonly DependencyProperty ButtonBackgroundProperty = DependencyProperty.Register("ButtonBackground", typeof(Brush), typeof(ToolbarStrip), null);
        public static readonly DependencyProperty ButtonForegroundProperty = DependencyProperty.Register("ButtonForeground", typeof(Brush), typeof(ToolbarStrip), null);
        private Size ddsize = new Size();
        public static readonly DependencyProperty FocusBrushProperty = DependencyProperty.Register("FocusBrush", typeof(Brush), typeof(ToolbarStrip), null);
        private bool isMenuOpen;
        private ContextMenu menu;
        public static readonly DependencyProperty MouseOverBrushProperty = DependencyProperty.Register("MouseOverBrush", typeof(Brush), typeof(ToolbarStrip), null);
        public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register("Orientation", typeof(Orientation), typeof(ToolbarStrip), new PropertyMetadata(Orientation.Horizontal, new PropertyChangedCallback(ToolbarStrip.OnOrientationChanged)));
        private ToolbarDropDown overflow;
        private Panel overflowPanel;
        public static readonly DependencyProperty OverflowPanelProperty = DependencyProperty.Register("OverflowPanel", typeof(DataTemplate), typeof(ToolbarStrip), new PropertyMetadata(null, new PropertyChangedCallback(ToolbarStrip.OnOverflowPanelChanged)));
        public static readonly DependencyProperty OverflowProperty = DependencyProperty.Register("Overflow", typeof(ToolbarOverflow), typeof(ToolbarStrip), new PropertyMetadata(ToolbarOverflow.Panel, new PropertyChangedCallback(ToolbarStrip.OnOverflowChanged)));
        private List<object> overItems = new List<object>();
        public static readonly DependencyProperty PressedBrushProperty = DependencyProperty.Register("PressedBrush", typeof(Brush), typeof(ToolbarStrip), null);
        private Grid root;

        // Events
        public event EventHandler OverflowItemAdded;

        public event EventHandler OverflowItemRemoved;

        // Methods
        public ToolbarStrip()
        {
            base.DefaultStyleKey = typeof(ToolbarStrip);
            SetCustomDefaultValues();
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            base.ArrangeOverride(finalSize);
            return finalSize;
        }

        private void FireOverflowItemAdded(object sender, EventArgs args)
        {
            if (this.OverflowItemAdded != null)
            {
                this.OverflowItemAdded(sender, args);
            }
        }

        private void FireOverflowItemRemoved(object sender, EventArgs args)
        {
            if (this.OverflowItemRemoved != null)
            {
                this.OverflowItemRemoved(sender, args);
            }
        }

        protected override DependencyObject GetContainerForItemOverride()
        {
            ToolbarStripItem item = new ToolbarStripItem();
            item.SetOrientation(this.Orientation);
            return item;
        }

        private string GetContent(object content)
        {
            if (content != null)
            {
                return content.ToString();
            }
            return null;
        }

        private Image GetImage(object content)
        {
            Image image = content as Image;
            if (image != null)
            {
                image = new Image
                {
                    Source = image.Source,
                    Stretch = Stretch.None,
                    HorizontalAlignment = HorizontalAlignment.Center
                };
            }
            return image;
        }

        private StackPanel GetItemsPanel()
        {
            ItemsPresenter templateChild = base.GetTemplateChild("ip") as ItemsPresenter;
            if ((templateChild != null) && (VisualTreeHelper.GetChildrenCount(templateChild) > 0))
            {
                return (VisualTreeHelper.GetChild(templateChild, 0) as StackPanel);
            }
            return null;
        }

        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return ((item is ToolbarStripItem) || (item is Separator));
        }

        private bool IsToolStripControl(object obj)
        {
            return (obj is IToolbarControl);
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            if (this.overflow == null)
            {
                return availableSize;
            }
            this.overflow.IsDropDownOpen = false;
            if (this.isMenuOpen && (this.menu != null))
            {
                this.menu.Hide();
            }
            if ((this.ddsize.Width == 0.0) && (this.ddsize.Height == 0.0))
            {
                this.overflow.Measure(availableSize);
                this.ddsize = this.overflow.DesiredSize;
            }
            if (this.overflow.ActualWidth > this.ddsize.Width)
            {
                this.ddsize.Width = this.overflow.ActualWidth;
            }
            if (this.overflow.ActualHeight > this.ddsize.Height)
            {
                this.ddsize.Height = this.overflow.ActualHeight;
            }
            if (this.overflowPanel != null)
            {
                foreach (UIElement element in this.overflowPanel.Children)
                {
                    Grid grid = element as Grid;
                    if (grid != null)
                    {
                        grid.Children.Clear();
                    }
                }
                this.overflowPanel.Children.Clear();
            }
            List<object> list = new List<object>();
            list.AddRange(this.overItems);
            this.overItems.Clear();
            StackPanel itemsPanel = this.GetItemsPanel();
            if (itemsPanel != null)
            {
                itemsPanel.Orientation = this.Orientation;
            }
            bool flag = this.Orientation == Orientation.Vertical;
            Size size = availableSize;
            Size size2 = base.MeasureOverride(availableSize);
            double num = base.Padding.Left + base.Padding.Right;
            double num2 = base.Padding.Top + base.Padding.Bottom;
            double num3 = 0.0;
            double width = size2.Width;
            int count = base.Items.Count;
            for (int i = 0; i < count; i++)
            {
                object obj2 = base.Items[i];
                ToolbarStripItem control = base.ItemContainerGenerator.ContainerFromItem(obj2) as ToolbarStripItem;
                if (control != null)
                {
                    control.SetOrientation(this.Orientation);
                    control.Visibility = Visibility.Visible;
                    UIElement element2 = obj2 as UIElement;
                    if (element2 != null)
                    {
                        Binding binding = new Binding("Visibility")
                        {
                            Source = element2
                        };
                        control.SetBinding(UIElement.VisibilityProperty, binding);
                    }
                    string stateName = "None";
                    if (this.IsToolStripControl(obj2))
                    {
                        bool flag2 = (i == 0) || ((i > 0) && !this.IsToolStripControl(base.Items[i - 1]));
                        bool flag3 = (i == (count - 1)) || ((i < (count - 1)) && !this.IsToolStripControl(base.Items[i + 1]));
                        if (flag2 && flag3)
                        {
                            stateName = "Alone";
                        }
                        else if (flag2)
                        {
                            stateName = "First";
                        }
                        else if (flag3)
                        {
                            stateName = "Last";
                        }
                        else
                        {
                            stateName = "Middle";
                        }
                    }
                    VisualStateManager.GoToState(control, stateName, false);
                    if ((obj2 != null) && (control != null))
                    {
                        control.SetOrientation(this.Orientation);
                        if (control != obj2)
                        {
                            control.Content = obj2;
                        }
                        control.Measure(availableSize);
                        Size desiredSize = control.DesiredSize;
                        if (flag)
                        {
                            num2 += desiredSize.Height;
                        }
                        else
                        {
                            num += desiredSize.Width;
                        }
                        bool flag4 = (this.overItems.Count > 0) || (this.overflow.Visibility == Visibility.Visible);
                        bool flag5 = flag ? ((num2 + (flag4 ? this.ddsize.Height : 0.0)) >= size.Height) : ((num + (flag4 ? this.ddsize.Width : 0.0)) >= size.Width);
                        if ((this.Overflow != ToolbarOverflow.None) && flag5)
                        {
                            if (flag)
                            {
                                num2 -= desiredSize.Height;
                            }
                            else
                            {
                                num -= desiredSize.Width;
                            }
                            control.Visibility = Visibility.Collapsed;
                            if (control != obj2)
                            {
                                control.Content = null;
                            }
                            if (this.overflowPanel != null)
                            {
                                Grid grid2 = new Grid();
                                if (obj2 is UIElement)
                                {
                                    try
                                    {
                                        grid2.Children.Add(obj2 as UIElement);
                                    }
                                    catch
                                    {
                                    }
                                }
                                else
                                {
                                    ContentPresenter presenter = new ContentPresenter
                                    {
                                        Content = obj2
                                    };
                                    grid2.Children.Add(presenter);
                                }
                                ToolbarStripItem item2 = new ToolbarStripItem();
                                if (!(obj2 is Separator))
                                {
                                    item2.Width = desiredSize.Width;
                                    item2.Height = desiredSize.Height;
                                }
                                grid2.Children.Add(item2);
                                this.overflowPanel.Children.Add(grid2);
                                item2.InitialState = stateName;
                            }
                            this.overItems.Add(obj2);
                        }
                        else if (flag)
                        {
                            width = Math.Max(width, desiredSize.Width);
                        }
                        else
                        {
                            num3 = Math.Max(num3, desiredSize.Height);
                        }
                    }
                }
                else
                {
                    UIElement element3 = obj2 as UIElement;
                    if (element3 != null)
                    {
                        element3.Measure(availableSize);
                        num += element3.DesiredSize.Width;
                        num2 += element3.DesiredSize.Height;
                    }
                }
            }
            for (int j = count - 1; j >= 0; j--)
            {
                object item = base.Items[j];
                if (list.Contains(item) && !this.overItems.Contains(item))
                {
                    this.FireOverflowItemRemoved(item, EventArgs.Empty);
                }
                else if (!list.Contains(item) && this.overItems.Contains(item))
                {
                    this.FireOverflowItemAdded(item, EventArgs.Empty);
                }
            }
            if (this.overItems.Count > 0)
            {
                if (this.Overflow == ToolbarOverflow.Panel)
                {
                    this.overflow.Content = this.overflowPanel;
                }
                else
                {
                    this.overflow.Content = null;
                }
                if (!this.UpadateMenu() && (this.Overflow == ToolbarOverflow.Menu))
                {
                    this.overflow.Visibility = Visibility.Collapsed;
                }
                else
                {
                    this.overflow.Visibility = Visibility.Visible;
                }
            }
            else
            {
                this.overflow.Visibility = Visibility.Collapsed;
            }
            if (flag)
            {
                if (this.overflow.Visibility == Visibility.Visible)
                {
                    num2 += this.ddsize.Height;
                }
                size.Height = num2;
                size.Width = Math.Max(width, size2.Width);
                return size;
            }
            if (this.overflow.Visibility == Visibility.Visible)
            {
                num += this.ddsize.Width;
            }
            size.Width = num;
            size.Height = Math.Max(num3, size2.Height);
            return size;
        }

        private void mi_Click(object sender, SourcedEventArgs e)
        {
            MenuItem item = (MenuItem)sender;
            sender = item.Tag;
            IToolbarControl control = sender as IToolbarControl;
            if (control != null)
            {
                control.FireClick();
            }
            else
            {
                Button owner = sender as Button;
                if (owner != null)
                {
                    ButtonAutomationPeer peer = new ButtonAutomationPeer(owner);
                    (peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider).Invoke();
                }
                else
                {
                    ToggleButton button2 = sender as ToggleButton;
                    if (button2 != null)
                    {
                        ToggleButtonAutomationPeer peer2 = new ToggleButtonAutomationPeer(button2);
                        (peer2.GetPattern(PatternInterface.Toggle) as IToggleProvider).Toggle();
                    }
                }
            }
        }

        public override void OnApplyTemplate()
        {
            EventHandler handler = null;
            EventHandler handler2 = null;
            EventHandler<PropertyChangedEventArgs<bool>> handler3 = null;
            base.OnApplyTemplate();
            this.overflow = base.GetTemplateChild("overflow") as ToolbarDropDown;
            this.menu = base.GetTemplateChild("menu") as ContextMenu;
            this.root = base.GetTemplateChild("root") as Grid;
            if (this.menu != null)
            {
                if (handler == null)
                {
                    handler = (s, e) => this.isMenuOpen = true;
                }
                this.menu.Opened += handler;
                if (handler2 == null)
                {
                    handler2 = delegate(object s, EventArgs e)
                    {
                        this.menu.DetectBoundaries = false;
                        this.isMenuOpen = false;
                        this.overflow.IsDropDownOpen = false;
                    };
                }
                this.menu.Closed += handler2;
            }
            if (this.overflow != null)
            {
                if (handler3 == null)
                {
                    handler3 = delegate(object s, PropertyChangedEventArgs<bool> e)
                    {
                        if (this.overflow.IsDropDownOpen)
                        {
                            switch (this.Overflow)
                            {
                                case ToolbarOverflow.Menu:
                                    if ((this.overflow.popup != null) && (this.overflow.popup.Child != null))
                                    {
                                        this.overflow.popup.Child.Opacity = 0.0;
                                        this.overflow.popup.Width = 0.0;
                                    }
                                    if (this.menu.Items.Count > 0)
                                    {
                                        UIElement visual = Application.Current.RootVisual;
                                        Point point = this.overflow.TransformToVisual(visual).Transform(new Point());
                                        this.menu.DetectBoundaries = true;
                                        this.menu.Show(null, new Point(point.X + this.overflow.ActualWidth, point.Y + this.overflow.ActualHeight));
                                        return;
                                    }
                                    this.overflow.IsDropDownOpen = false;
                                    return;

                                case ToolbarOverflow.Panel:
                                    {
                                        if ((this.overflow.popup != null) && (this.overflow.popup.Child != null))
                                        {
                                            this.overflow.popup.Child.Opacity = 1.0;
                                            this.overflow.popup.ClearValue(FrameworkElement.WidthProperty);
                                        }
                                        FrameworkElement rootVisual = Application.Current.RootVisual as FrameworkElement;
                                        double num = rootVisual.ActualWidth - 10.0;
                                        this.overflowPanel.MaxWidth = num;
                                        break;
                                    }
                                default:
                                    return;
                            }
                        }
                    };
                }
                this.overflow.IsDropDownOpenChanged += handler3;
            }
        }

        private static void OnOrientationChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            ToolbarStrip strip = (ToolbarStrip)sender;
            bool flag = strip.Orientation == Orientation.Vertical;
            if (strip.overflow != null)
            {
                if (flag)
                {
                    Grid.SetRow(strip.overflow, 1);
                    Grid.SetColumn(strip.overflow, 0);
                    strip.overflow.VerticalAlignment = VerticalAlignment.Bottom;
                    strip.overflow.ClearValue(FrameworkElement.HorizontalAlignmentProperty);
                }
                else
                {
                    Grid.SetRow(strip.overflow, 0);
                    Grid.SetColumn(strip.overflow, 1);
                    strip.overflow.HorizontalAlignment = HorizontalAlignment.Right;
                    strip.overflow.ClearValue(FrameworkElement.VerticalAlignmentProperty);
                }
            }
            strip.InvalidateMeasure();
        }

        private static void OnOverflowChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            ((ToolbarStrip)sender).InvalidateMeasure();
        }

        private static void OnOverflowPanelChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            ToolbarStrip strip = (ToolbarStrip)sender;
            if (strip.overflowPanel != null)
            {
                strip.overflowPanel.Children.Clear();
            }
            strip.overflowPanel = null;
            DataTemplate newValue = args.NewValue as DataTemplate;
            if (newValue != null)
            {
                strip.overflowPanel = newValue.LoadContent() as Panel;
            }
            strip.InvalidateMeasure();
        }

        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            base.PrepareContainerForItemOverride(element, item);
            ToolbarStripItem target = element as ToolbarStripItem;
            if (target != null)
            {
                if (target != item)
                {
                    target.Content = item;
                }
                target.SetBinding<ToolbarStrip>(Control.BackgroundProperty, this, ts => ts.ButtonBackground);
                target.SetBinding<ToolbarStrip>(Control.ForegroundProperty, this, ts => ts.ButtonForeground);
                target.SetBinding<ToolbarStrip>(Control.BorderBrushProperty, this, ts => ts.BorderBrush);
                target.SetBinding<ToolbarStrip>(ToolbarStripItem.MouseOverBrushProperty, this, ts => ts.MouseOverBrush);
                target.SetBinding<ToolbarStrip>(ToolbarStripItem.PressedBrushProperty, this, ts => ts.PressedBrush);
                target.SetBinding<ToolbarStrip>(ToolbarStripItem.FocusBrushProperty, this, ts => ts.FocusBrush);
                ToolbarButton button = item as ToolbarButton;
                if (button != null)
                {
                    button.SetBinding<ToolbarStrip>(Control.BackgroundProperty, this, ts => ts.ButtonBackground);
                    button.SetBinding<ToolbarStrip>(Control.ForegroundProperty, this, ts => ts.ButtonForeground);
                    button.SetBinding<ToolbarStrip>(Control.BorderBrushProperty, this, ts => ts.BorderBrush);
                    button.SetBinding<ToolbarStrip>(ToolbarButton.MouseOverBrushProperty, this, ts => ts.MouseOverBrush);
                    button.SetBinding<ToolbarStrip>(ToolbarButton.PressedBrushProperty, this, ts => ts.PressedBrush);
                }
                ToolbarToggleButton button2 = item as ToolbarToggleButton;
                if (button2 != null)
                {
                    button2.SetBinding<ToolbarStrip>(Control.BackgroundProperty, this, ts => ts.ButtonBackground);
                    button2.SetBinding<ToolbarStrip>(Control.ForegroundProperty, this, ts => ts.ButtonForeground);
                    button2.SetBinding<ToolbarStrip>(Control.BorderBrushProperty, this, ts => ts.BorderBrush);
                    button2.SetBinding<ToolbarStrip>(ToolbarToggleButton.MouseOverBrushProperty, this, ts => ts.MouseOverBrush);
                    button2.SetBinding<ToolbarStrip>(ToolbarToggleButton.PressedBrushProperty, this, ts => ts.PressedBrush);
                }
                ToolbarDropDown down = item as ToolbarDropDown;
                if (down != null)
                {
                    down.SetBinding<ToolbarStrip>(Control.BackgroundProperty, this, ts => ts.ButtonBackground);
                    down.SetBinding<ToolbarStrip>(Control.ForegroundProperty, this, ts => ts.ButtonForeground);
                    down.SetBinding<ToolbarStrip>(Control.BorderBrushProperty, this, ts => ts.BorderBrush);
                    down.SetBinding<ToolbarStrip>(ToolbarDropDown.MouseOverBrushProperty, this, ts => ts.MouseOverBrush);
                    down.SetBinding<ToolbarStrip>(ToolbarDropDown.PressedBrushProperty, this, ts => ts.PressedBrush);
                }
            }
            Separator separator = element as Separator;
            if (separator != null)
            {
                Binding binding = new Binding
                {
                    Converter = CustomConverter.Create((value, type, parameter, culture) => (((Orientation)value) == Orientation.Horizontal) ? Orientation.Vertical : Orientation.Horizontal)
                };
                separator.SetBinding(Separator.OrientationProperty, binding.From<ToolbarStrip>(this, x => x.Orientation));
                separator.SetBinding<ToolbarStrip>(Control.BackgroundProperty, this, ts => ts.Background);
            }
        }

        private void SetCustomDefaultValues()
        {
            StackPanel panel = new StackPanel
            {
                Orientation = Orientation.Horizontal
            };
            this.overflowPanel = panel;
        }

        private bool UpadateMenu()
        {
            if (this.menu != null)
            {
                this.menu.Items.Clear();
                int count = this.OverflowMenuItems.Count;
                for (int i = 0; i < count; i++)
                {
                    this.menu.Items.Add(this.OverflowMenuItems[i]);
                }
            }
            return ((this.menu != null) && (this.menu.Items.Count > 0));
        }


        // Properties
        public Brush ButtonBackground
        {
            get { return (Brush)GetValue(ButtonBackgroundProperty); }
            set { SetValue(ButtonBackgroundProperty, value); }
        }

        public Brush ButtonForeground
        {
            get { return (Brush)GetValue(ButtonForegroundProperty); }
            set { SetValue(ButtonForegroundProperty, value); }
        }

        public Brush FocusBrush
        {
            get { return (Brush)GetValue(FocusBrushProperty); }
            set { SetValue(FocusBrushProperty, value); }
        }

        public Brush MouseOverBrush
        {
            get { return (Brush)GetValue(MouseOverBrushProperty); }
            set { SetValue(MouseOverBrushProperty, value); }
        }

        public Orientation Orientation
        {
            get { return (Orientation)GetValue(OrientationProperty); }
            set { SetValue(OrientationProperty, value); }
        }

        public ToolbarOverflow Overflow
        {
            get { return (ToolbarOverflow)GetValue(OverflowProperty); }
            set { SetValue(OverflowProperty, value); }
        }

        public ObservableCollection<object> OverflowMenuItems
        {
            get
            {
                if (this._menuItems == null)
                {
                    this._menuItems = new ObservableCollection<object>();
                }
                return this._menuItems;
            }
        }

        public DataTemplate OverflowPanel
        {
            get { return (DataTemplate)GetValue(OverflowPanelProperty); }
            set { SetValue(OverflowPanelProperty, value); }
        }

        public Brush PressedBrush
        {
            get { return (Brush)GetValue(PressedBrushProperty); }
            set { SetValue(PressedBrushProperty, value); }
        }
    }
}
